﻿using LDT.CoreLibrary;
using LdtDataEngin.ModuleDetail.BaseModule.Optimization;
using LdtJudge.DataEngine.CallInterface.ConfiCenter;
using LdtJudge.DataEngine.Common;
using LdtJudge.DataEngine.DataBaseStores;
using LdtJudge.DataEngine.Model.OptimizationModel;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.Linq;

namespace LdtDataEngin.ModuleDetail.OptimizationModule.FillBackOptimization
{
    /// <summary>
    /// 回填优选中将json格式的优选内容转成对应的xml格式，之后使用对应的回填优选
    /// </summary>
    public class ModifyJsonDataToXml : OptimizationBase
    {
        /// <summary>
        /// 调用的时候需要找到全的要素中心对应上层应用的模型配置，
        /// 从这个配置里面找到xpath对应的表名或是列名
        /// </summary>
        public string configName { get; set; }
        public ConvertConfigModel configInfo = new ConvertConfigModel();

        public ModifyJsonDataToXml()
        {
        }
        /// <summary>
        /// 转化
        /// </summary>
        /// <param name="json">需要修改的Json数据</param>
        /// <returns></returns>
        public string JsonToXml(string json)
        {
            XmlDocument doc = new XmlDocument();
            try
            {
                doc.LoadXml("<root remark=\"变更数据内容配置\"><changedata remark=\"变更的数据集合\"></changedata></root>");
                XmlNode parentNode = doc.FirstChild.FirstChild;
                JObject jObject = JObject.Parse(json);
                configName = jObject["config"].ToString();
                JArray result = JArray.Parse(jObject["result"].ToString());
                if (result.Count > 0)
                {
                    foreach (JToken item in result.Children())
                    {
                        #region  获取表修改的内容
                        string tableName = string.Empty;
                        JObject tableObject = JObject.Parse(item.ToString());
                        foreach (var tempT in tableObject)
                        {
                            // 获取表名
                            tableName = tempT.Key;
                        }
                        // 获取表的行内容
                        string rowsInfo = tableObject.Children().FirstOrDefault().Children().FirstOrDefault().ToString();
                        JArray rowsJa = JArray.Parse(rowsInfo);
                        // 遍历行获取每行的列内容
                        foreach (JToken rowInfo in rowsJa.Children())
                        {
                            JObject columnJO = JObject.Parse(rowInfo.ToString());
                            //修改类型属性   0未发生修改  1新增  2修改  3删除
                            string changeType = columnJO["changetype"].ToString();
                            string id = columnJO["id"].ToString();
                            string parentid = columnJO["parentid"].ToString();
                            Dictionary<string, string> columnvalues = columnJO.ToObject<Dictionary<string, string>>();
                            columnvalues.Remove("id");
                            columnvalues.Remove("parentid");
                            columnvalues.Remove("changetype");
                            switch (changeType)
                            {
                                case "1":
                                    // 新增节点与属性，新增节点的时候将id设置为空
                                    if (string.IsNullOrEmpty(id))
                                    {
                                        XmlNode node = AddNode(doc, columnvalues, tableName, id);
                                        parentNode.AppendChild(node);
                                    }
                                    else
                                    {
                                        // 新增属性
                                        foreach (KeyValuePair<string, string> kv in columnvalues)
                                        {
                                            XmlNode node = ModifyAttribute(doc, "A", tableName, kv.Key, kv.Value, id);
                                            parentNode.AppendChild(node);
                                        }
                                    }
                                    break;
                                case "2":
                                    // 修改节点属性
                                    foreach (KeyValuePair<string, string> kv in columnvalues)
                                    {
                                        XmlNode node = ModifyAttribute(doc, "M", tableName, kv.Key, kv.Value, id);
                                        parentNode.AppendChild(node);
                                    }
                                    break;
                                case "3":
                                    // 删除节点或是属性，删除节点的时候直接设置id，parentid,changetype
                                    if (columnvalues.Count > 0)
                                    {
                                        // 删除属性
                                        foreach (KeyValuePair<string, string> kv in columnvalues)
                                        {
                                            XmlNode node = ModifyAttribute(doc, "D", tableName, kv.Key, "", id);
                                            parentNode.AppendChild(node);
                                        }
                                    }
                                    else
                                    {
                                        // 删除的节点信息
                                        XmlNode node = DeleteNode(doc, tableName, id);
                                        parentNode.AppendChild(node);
                                    }
                                    break;
                                default:
                                    break;
                            }
                        }
                        #endregion
                    }
                }
            }
            catch (System.Exception ex)
            {
                dataContext.InteractiveShow.LogShow("ModifyJsonDataToXml：JsonToXml方法异常:" + ex.Message + System.Environment.NewLine + ex.StackTrace);
                throw;
            }
            return doc.OuterXml;
        }

        /// <summary>
        /// 根据表名与属性名获取对应的xpath
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="atrributeName">属性名</param>
        /// <returns>xpath</returns>
        public string GetXpath(string tableName, string atrributeName = "")
        {
            try
            {
                configInfo = ParseConfig(configName);
                Element tableConfigInfo = configInfo.ConfigInfo.elements.Where(a => a.ModelName == tableName).ToList().FirstOrDefault();
                if (string.IsNullOrEmpty(atrributeName))
                {
                    return tableConfigInfo.Xpath;
                }
                else
                {
                    ProPerty pro = tableConfigInfo.proPerties.Where(a => a.FiledName == atrributeName).ToList().FirstOrDefault();
                    return tableConfigInfo.Xpath + "\\@" + pro.Attrname;
                }
            }
            catch (System.Exception ex)
            {
                dataContext.InteractiveShow.LogShow("ModifyJsonDataToXml：GetXpath方法异常:" + ex.Message + System.Environment.NewLine + ex.StackTrace);
                return null;
            }

        }

        /// <summary>
        /// 解析配置
        /// </summary>
        /// <param name="fileName">配置文件</param>
        /// <returns></returns>
        public ConvertConfigModel ParseConfig(string fileName)
        {
            ConvertConfigModel convertConfig = new ConvertConfigModel();
            try
            {
                Elements elementList = new Elements();
                List<Element> elements = new List<Element>();

                #region 根据文件名从配置管理平台获取配置内容
                Dictionary<string, string> dicParmet = new Dictionary<string, string>();
                dicParmet.Add("fileName", fileName);
                string messagexml = WebUtil.DoGet(ConfigRetrieval.GetConfigRetrieval.GetAppSettingString("systemapi") + "/api/wordparse/GetPartOptResultConfig", dicParmet, "utf-8");
                string xmlMessage = HttpHelp.DeCodeBase64new(65001, messagexml.Replace('"', ' '));
                JObject jo = (JObject)JsonConvert.DeserializeObject(xmlMessage);
                xmlMessage = jo["CfgContent"].ToString();
                #endregion

                XmlDocument doc = new XmlDocument();
                doc.LoadXml(xmlMessage);
                // 配置文件信息
                XDocument docs = XDocument.Parse(doc.OuterXml);
                List<XElement> nodes = docs.Root.Element("elements").Elements().ToList();
                foreach (XElement item in nodes)
                {
                    Element configNode = new Element();
                    // element节点的属性
                    if (item.Attribute("xpath") != null)
                        configNode.Xpath = item.Attribute("xpath").Value;
                    if (item.Attribute("modelname") != null)
                        configNode.ModelName = item.Attribute("modelname").Value;
                    if (item.Attribute("IsSubset") != null)
                        configNode.IsSubset = item.Attribute("IsSubset").Value;
                    // property节点处理
                    configNode.proPerties = new List<ProPerty>();
                    List<XElement> properties = item.Elements("property").ToList();
                    foreach (XElement propertyNode in properties)
                    {
                        ProPerty proPerty = new ProPerty();
                        if (propertyNode.Attribute("attrname") != null)
                            proPerty.Attrname = propertyNode.Attribute("attrname").Value;
                        if (propertyNode.Attribute("filedname") != null)
                            proPerty.FiledName = propertyNode.Attribute("filedname").Value;
                        configNode.proPerties.Add(proPerty);
                    }
                    // 处理子节点
                    configNode.ChildElements = new List<Element>();
                    ParseElement(configNode, item);
                    elements.Add(configNode);
                }
                elementList.elements = elements;
                convertConfig.ConfigInfo = elementList;
            }
            catch (System.Exception ex)
            {
                dataContext.InteractiveShow.LogShow("ModifyJsonDataToXml：ParseConfig方法异常:" + ex.Message + System.Environment.NewLine + ex.StackTrace);
            }
            return convertConfig;
        }

        /// <summary>
        /// 递归处理子节点
        /// </summary>
        /// <param name="parentNode"></param>
        /// <param name="configNode"></param>
        public void ParseElement(Element parentNode, XElement configNode)
        {
            List<XElement> childElements = configNode.Elements("element").ToList();
            foreach (XElement item in childElements)
            {
                Element childConfigNode = new LdtJudge.DataEngine.Model.OptimizationModel.Element();
                // element节点的属性
                if (item.Attribute("xpath") != null)
                    childConfigNode.Xpath = item.Attribute("xpath").Value;
                if (item.Attribute("modelname") != null)
                    childConfigNode.ModelName = item.Attribute("modelname").Value;
                if (item.Attribute("IsSubset") != null)
                    childConfigNode.IsSubset = item.Attribute("IsSubset").Value;
                // property节点处理
                childConfigNode.proPerties = new List<ProPerty>();
                List<XElement> properties = item.Elements("property").ToList();
                foreach (XElement propertyNode in properties)
                {
                    ProPerty proPerty = new ProPerty();
                    if (propertyNode.Attribute("attrname") != null)
                        proPerty.Attrname = propertyNode.Attribute("attrname").Value;
                    if (propertyNode.Attribute("filedname") != null)
                        proPerty.FiledName = propertyNode.Attribute("filedname").Value;
                    childConfigNode.proPerties.Add(proPerty);
                }
                // 处理子节点
                ParseElement(childConfigNode, item);
                parentNode.ChildElements.Add(childConfigNode);
            }
        }

        /// <summary>
        /// 删除节点
        /// </summary>
        /// <param name="doc">目标xml</param>
        /// <param name="tableName">表名</param>
        /// <param name="id">id</param>
        /// <returns></returns>
        public XmlNode DeleteNode(XmlDocument doc, string tableName, string id)
        {
            XmlNode node = doc.CreateElement("handlegroup");
            XmlAttribute targetType = doc.CreateAttribute("code");
            targetType.Value = "1";
            node.Attributes.Append(targetType);
            // 添加xmlPath节点
            XmlNode xpathNode = doc.CreateElement("xmlpath");
            XmlAttribute idAtt = doc.CreateAttribute("id");
            idAtt.Value = id;
            xpathNode.InnerText = GetXpath(tableName);
            xpathNode.Attributes.Append(idAtt);
            node.AppendChild(xpathNode);
            // 添加handletype节点
            XmlNode handletypeNode = doc.CreateElement("handletype");
            handletypeNode.InnerText = "D";
            node.AppendChild(handletypeNode);
            // 添加handlevalue节点
            XmlNode handlevalueNode = doc.CreateElement("handlevalue");
            XmlAttribute valueAtt = doc.CreateAttribute("value");
            valueAtt.Value = "";
            handlevalueNode.Attributes.Append(valueAtt);
            node.AppendChild(handlevalueNode);
            // 返回节点
            return node;
        }

        /// <summary>
        /// xml节点属性操作
        /// </summary>
        /// <param name="doc">目标xml</param>
        /// <param name="operateType">属性操作的方式 A添加 D删除 M修改</param>
        /// <param name="tableName">表名</param>
        /// <param name="fieldName">字段名</param>
        /// <param name="fieldValue">属性值 当operateType=D时，这个设置为空</param>
        /// <param name="id">节点ID</param>
        /// <returns>属性操作节点</returns>
        public XmlNode ModifyAttribute(XmlDocument doc, string operateType, string tableName, string fieldName, string fieldValue, string id)
        {
            XmlNode node = doc.CreateElement("handlegroup");
            XmlAttribute targetType = doc.CreateAttribute("code");
            targetType.Value = "0";
            node.Attributes.Append(targetType);
            // 添加xmlPath节点
            XmlNode xpathNode = doc.CreateElement("xmlpath");
            XmlAttribute idAtt = doc.CreateAttribute("id");
            idAtt.Value = id;
            xpathNode.InnerText = GetXpath(tableName, fieldName);
            xpathNode.Attributes.Append(idAtt);
            node.AppendChild(xpathNode);
            // 添加handletype节点
            XmlNode handletypeNode = doc.CreateElement("handletype");
            handletypeNode.InnerText = operateType;
            node.AppendChild(handletypeNode);
            // 添加handlevalue节点
            XmlNode handlevalueNode = doc.CreateElement("handlevalue");
            XmlAttribute valueAtt = doc.CreateAttribute("value");
            valueAtt.Value = fieldValue;
            handlevalueNode.Attributes.Append(valueAtt);
            node.AppendChild(handlevalueNode);

            return node;
        }

        /// <summary>
        /// 新增节点
        /// </summary>
        /// <param name="doc">目标xml</param>
        /// <param name="attributes">新增节点的属性值</param>
        /// <param name="tableName">表名，也是新增节点的名称</param>
        /// <param name="id">父节点ID</param>
        /// <returns></returns>
        public XmlNode AddNode(XmlDocument doc, Dictionary<string, string> attributes, string tableName, string id)
        {
            XmlNode node = doc.CreateElement("handlegroup");
            XmlAttribute targetType = doc.CreateAttribute("code");
            targetType.Value = "1";
            node.Attributes.Append(targetType);
            // 获取父节点XPATH与当前新增节点的名称
            string addNodePath = GetXpath(tableName);
            List<string> partPath = addNodePath.Split('\\').ToList();
            string nodeName = partPath.Last();
            string parentPath = addNodePath.Substring(0, addNodePath.IndexOf(nodeName) - 1);
            // 添加xmlPath节点
            XmlNode xpathNode = doc.CreateElement("xmlpath");
            XmlAttribute idAtt = doc.CreateAttribute("id");
            idAtt.Value = id;
            xpathNode.InnerText = parentPath;
            xpathNode.Attributes.Append(idAtt);
            node.AppendChild(xpathNode);
            // 添加handletype节点
            XmlNode handletypeNode = doc.CreateElement("handletype");
            handletypeNode.InnerText = "A";
            node.AppendChild(handletypeNode);
            // 添加handlevalue节点
            string nodeXmlStr = "<" + nodeName;
            foreach (KeyValuePair<string, string> item in attributes)
            {
                nodeXmlStr += " " + GetAttributeName(tableName, item.Key) + "=\"" + item.Value + "\" ";
            }
            nodeXmlStr += "/>";
            XmlNode handlevalueNode = doc.CreateElement("handlevalue");
            XmlAttribute valueAtt = doc.CreateAttribute("value");
            valueAtt.Value = HttpHelp.EnDataBase64(nodeXmlStr);
            handlevalueNode.Attributes.Append(valueAtt);
            node.AppendChild(handlevalueNode);

            return node;
        }

        /// <summary>
        /// 获取字段的在xml中对应的属性名称
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="fieldName">字段名</param>
        /// <returns></returns>
        private string GetAttributeName(string tableName, string fieldName)
        {
            configInfo = ParseConfig(configName);
            LdtJudge.DataEngine.Model.OptimizationModel.Element tableConfigInfo = configInfo.ConfigInfo.elements.Where(a => a.ModelName == tableName).ToList().FirstOrDefault();
            ProPerty pro = tableConfigInfo.proPerties.Where(a => a.FiledName == fieldName).ToList().FirstOrDefault();
            return pro.Attrname;
        }
    }
}
